﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using com.byt.webcore;
using com.byt.webcore.utils;
using System.Data.Common;
using MYLSOFT.JsonSimple;
using System.Collections.Specialized;
using com.byt.webcore.security;

namespace com.byt.webcore
{
    public abstract class ServletBase : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        private static string CONTENT_TYPE = "text/html; charset=windows-1252";

        protected abstract void doCommand(Parameters p);

        protected string getContentType()
        {
            return CONTENT_TYPE;
        }

        public void ProcessRequest(HttpContext context)
        {
            Execute(context.Request, context.Response);
        }

        protected Parameters Execute(HttpRequest request, HttpResponse response)
        {


            response.ContentType = getContentType();
            //response.addHeader("", "");

            Parameters param = null;

            try
            {
                /*
                if(isLock(request)){
                    //throw new Exception("En ejecución");
                    return;
                }
                lock(request);
                */
                param = createParameter(request, response);
                param.setConnection(getConnection(param));
                 
                doCommand(param);

                param.end();

            }
            catch (Exception ex)
            {
                doError(param, ex);
            }

            return param;

        }

        protected string getServletName(HttpRequest request)
        {
            string serv = request.Path;
            int pos = serv.LastIndexOf("/");
            if (pos > -1)
                serv = serv.Substring(pos + 1);
            return serv;
        }

        protected void doError(Parameters p, Exception ex)
        {

            try
            {

                string error = "";
                //ex.printStackTrace(p.res.getWriter());

                error = ex.Message;

                if (string.IsNullOrEmpty(error))

                    error = ex.ToString();

                else
                {

                    int idxora = error.IndexOf("ORA-");
                    if (idxora > -1)
                    {
                        error = error.Substring(11);
                        idxora = error.IndexOf("ORA-");
                        if (idxora > -1)
                        {
                            error = error.Substring(0, idxora - 1);
                        }
                    }

                }

                /*
                Log.write("Web", "error", ex.getMessage());
                Log.write("   ", ex);
                */
                p.json.Add("error", 1);
                p.json.Add("message", error);
                p.abort(ex);

            }
            catch (Exception e)
            {
            }

        }

        virtual protected DbConnection getConnection(Parameters p)
        {
            // Leer la CONEXION
            DbConnection conn = null;
            string[] parts = p.req.Path.Split('/');
            for (int i = parts.Length - 2; i >= 0; i--)
            {
                try
                {
                    if (parts[i].Length > 0)
                    {
                        conn = AppConfig.getConnection(p, parts[i]);
                        return conn;
                    }
                }
                catch
                {
                    //System.out.println("No existe registrada una conexión para el servlet \"" + p.req.getServletPath() + "\"");
                }
            }

            // Si no existe una conexion retornar la conexion por defecto
            conn = AppConfig.getConnection(p, "SUCE");
            return conn;
        }
        /*
        private bool isLock(HttpRequest request){
            File f = getFileLockName(request);
            return f.exists();
        }

        private void lock(HttpRequest request){
            File f = getFileLockName(request);
            try {
                f.createNewFile();
            } catch (IOException e) {
                // TODO
            }
        }

        private void unlock(HttpRequest request){
            File f = getFileLockName(request);
            f.delete();
        }
    */

        protected ServletBase.Parameters createParameter(HttpRequest request, HttpResponse response)
        {
            return new ServletBase.Parameters(request, response);
        }



        public class Parameters
        {
            public string command;
            public string subcommand;
            public HttpRequest req;
            public HttpResponse res;
            public JSONObject json;
            private Dictionary<string, string> parameters;
            public Connection conn;

            // variables de logueo
            public int idsession;
            public int? iduser;
            public int? iduorganica;
            public string idadmuser;
            public string iduservuce;

            public string schema = null;

            public Parameters(HttpRequest request, HttpResponse response)
            {
                req = request;
                res = response;
                json = new JSONObject();
                parameters = new Dictionary<string, string>();
                if(req.Form.Count > 0)
                    setParameters(req.Form);
                else
                    setParameters(req.Params);
                initCookie();
            }

            public void setConnection(DbConnection conn)
            {
                this.conn = new Connection(conn);
                if (this.conn != null)
                {
                    /*
                    // Solo para PostgreSQL, establecer las variables de session
                    string remoteHost = req.getRemoteHost();

                    Object o = Utils.executeScalar(conn, "SELECT auditoria.init_transaction('%1$s', %2$s, '%3$s', '%4$s', '%5$s')", this.id_administrado, id_user, remoteHost, command, subcommand);
                    if(o != null)
                        Utils.executeResultSet(conn, "SELECT SET_CONFIG('varsession.idtransaccion', '%1$s', false), SET_CONFIG('varsession.idadmuser', '%2$s', false)", o.ToString(), this.id_administrado);
                    */
                    this.conn.BeginTransaction();
                }
            }

            private void initCookie()
            {
                JSONObject user = Security.getUserFromCookie(this);
                if (user != null)
                {
                    this.iduser = Utils.parseInteger(user["iduser"]);
                    //this.idorgentidad = Utils.parseInteger(user.get("idorgentidad"));
                    this.iduorganica = Utils.parseInteger(user["iduorganica"]);
                    this.idadmuser = Utils.AsString(user["idadmuser"]);
                    this.iduservuce = (string)user["iduservuce"];
                }
            }

            public void abort(Exception ex)
            {
                try
                {
                    res.AppendHeader("X-JSON", json.ToString());
                    if (conn != null)
                    {
                        conn.Rollback();
                        conn.Close();
                    }
                    res.Write(ex.StackTrace);
                    res.Flush();
                    res.Close();
                }
                catch (Exception e)
                {
                    //e.printStackTrace();
                }
            }

            public void end()
            {
                res.AppendHeader("X-JSON", json.ToString());
                try
                {
                    if (conn != null)
                    {
                        conn.Commit();
                        conn.Close();
                    }
                    //res.Flush();
                    //res.Close();
                }
                catch
                {
                    //e.printStackTrace();
                }
            }

            public bool validUser()
            {
                return iduser != null;
            }

            public void validUserWithException()
            {
                if (iduser == null)
                    throw new Exception("Usuario desconocido, volver a iniciar sesión.");
            }

            public void writeForCallback(Object text)
            {
                if (text == null)
                    return;
                bool scriptTag = false;
                string cb = req.Params["callback"];
                scriptTag = (cb != null && cb.Length > 0);

                if (scriptTag)
                    res.Write(cb + "(");
                res.Write(text.ToString());
                if (scriptTag)
                    res.Write(");");
            }

            public void writeForStore(Object data)
            {
                JSONObject jo = new JSONObject();
                jo.Add("success", data != null);
                jo.Add("data", data);
                res.Write(jo.ToString());
            }

            public void print(string obj)
            {
                if (obj == null)
                    return;
                res.Write(obj.ToString());
            }

            public void print(string obj, params object[] parametros)
            {
                if (obj == null)
                    return;
                res.Write(string.Format(obj, parametros));
            }

            public void print(Object obj)
            {
                if (obj == null)
                    return;
                res.Write(obj.ToString());
            }

            public Dictionary<string, string> getMap()
            {
                return parameters;
            }

            public string getParameter(string key)
            {
                string value;
                parameters.TryGetValue(key, out value);
                return value;
            }

            public void setParameters(NameValueCollection value)
            {
                parameters.Clear();

                Object vals;

                foreach (string key in value.Keys)
                {
                    if (!parameters.ContainsKey(key))
                    {
                        vals = value[key];
                        parameters.Add(key, vals == null ? "" : vals.ToString());
                    }
                }

                initCommands();
            }

            private void initCommands()
            {
                string commandName = "";
                string subCommandName = "";

                // COMMAND
                if (parameters.ContainsKey("C"))
                    commandName = "C";
                else if (parameters.ContainsKey("c"))
                    commandName = "c";

                parameters.TryGetValue(commandName, out this.command);
                if (string.IsNullOrEmpty(this.command))
                    this.command = "";

                this.command = command.ToUpper();

                // SUBCOMMAND
                if (parameters.ContainsKey("S"))
                    subCommandName = "S";
                else if (parameters.ContainsKey("s"))
                    subCommandName = "s";

                parameters.TryGetValue(subCommandName, out this.subcommand);
                if (string.IsNullOrEmpty(this.subcommand))
                    this.subcommand = "";

                this.subcommand = subcommand.ToUpper();


                removeParameter(commandName);
                removeParameter(subCommandName);
            }

            public string removeParameter(string key)
            {
                try
                {
                    string value = parameters[key];
                    if (parameters.Remove(key))
                        return value;
                }
                catch
                {
                }
                return null;
            }

            public void setParameter(string key, Object value)
            {
                if (value != null)
                    parameters.Add(key, value.ToString());
            }

            public string getRealPath(string uri)
            {
                return this.req.PhysicalApplicationPath + uri;
            }

            public string getServletPath(string uri)
            {
                return this.req.PhysicalPath + uri;
            }


            public string getTemporalDir()
            {
                return AppConfig.getPath(this, "outreport");
            }

        }


    }



}
